package io.bdmc.core.msp2000;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import io.bdmc.common.enums.RouteTypeEnum;
import io.bdmc.common.utils.*;
import io.bdmc.common.websocket.MyWebSocket;
import io.bdmc.core.eu.EUDataRead;
import io.bdmc.core.msp2000.model.ElectronicTags;
import io.bdmc.core.msp2000.model.FanPlate;
import io.bdmc.core.msp2000.model.Msp2000Ter2Platform;
import io.bdmc.core.msp2000.model.SlotData;
import io.bdmc.core.msp2000.utils.FmsDeviceUtil;
import io.bdmc.core.msp2000.utils.OswDeviceUtil;
import io.bdmc.core.snmp.SORFileParserTool;
import io.bdmc.core.snmp.SnmpDataCache;
import io.bdmc.core.snmp.SnmpTrapThreadPool;
import io.bdmc.core.snmp.cache.ConcurrentHashMapCacheUtils;
import io.bdmc.core.udp.UdpClientSendData;
import io.bdmc.modules.bss.entity.*;
import io.bdmc.modules.bss.model.DiskTypeEnum;
import io.bdmc.modules.bss.model.SorFileParser;
import io.bdmc.modules.bss.service.*;
import io.bdmc.modules.sys.service.ISysAboutService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Component
public class Msp2000ThreadPool {

    @Autowired
    IDeviceMachineFrameService _frameService;

    @Autowired
    IDeviceAlarmRealtimeService _alarmRealtimeService;

    @Autowired
    IDeviceDeviceService _devSvs;

    @Autowired
    IDeviceMachineRackService _rackService;

    @Autowired
    IDeviceMachineDiskService _diskService;

    @Autowired
    IDeviceMachinePowerService _powerService;

    @Autowired
    IDeviceMachineFanService _fanService;

    @Autowired
    IDeviceMachineFspService _fspService;

    @Autowired
    IDeviceMachineEdfaService _edfaService;

    @Autowired
    IDeviceMachineRtService _rtService;

    @Autowired
    IDeviceMachineFecService _fecService;

    @Autowired
    IDeviceMachineFecModuleService _fecModuleService;

    @Autowired
    IDeviceMachineRfaService _rfaService;

    @Autowired
    UdpClientSendData _udpClient;

    @Autowired
    IDeviceAlarmTypeService _alarmTypeService;

    @Autowired
    IDeviceAlarmService _alarmHistoryService;

    @Autowired
    Msp2000AlarmProcess _msp2000AlarmProcess;

    @Autowired
    IDeviceMachineRemindService _remindService;

    @Autowired
    IDeviceMachineOswService _oswService;

    @Autowired
    IDeviceMachineOpmService _opmService;

    @Autowired
    IDeviceMachineOpmModuleService _opmModuleService;

    @Autowired
    IDeviceMachineOsModuleService _osModuleService;

    @Autowired
    IDeviceMachineFmsService _fmsService;

    @Autowired
    SnmpTrapThreadPool _snmpService;

    @Autowired
    IDeviceRouteConfigService routeConfigService;
    @Autowired
    IDeviceRouteService routeService;

    @Autowired
    FmsDeviceUtil fmsDeviceUtil;

    @Autowired
    IDeviceFibreMatchService matchService;

    @Autowired
    OswDeviceUtil oswDeviceUtil;

    @Autowired
    ISysAboutService aboutService;

    @Autowired
    EUDataRead euDataRead;

    protected static Logger logger = LoggerFactory.getLogger(Msp2000ThreadPool.class);

    /**
     * 专家测试后，定时查询是否完成测试
     */
    @Scheduled(fixedDelay = 1000 * 5)
    public void querySor() {
        List<DeviceDevice> fmsList = _devSvs.getFmsAndOtdr();
        for (DeviceDevice fms : fmsList) {
            boolean inMeasure = ConcurrentHashMapCacheUtils
                    .isExist(Constant.MSP2000MeasureNowMapPrefix + fms.getDeviceSn());
            if (inMeasure) {
                // 发送查询状态命令
                try {
                    DeviceDevice parent = _devSvs.getById(fms.getParentId());
                    String ip = fms.isOTDR() ? fms.getIpaddr() : parent.getIpaddr();
                    int port = fms.isOTDR() ? fms.getDevicePort() : parent.getDevicePort();

                    String state = fmsDeviceUtil.getFmsStatus(fms.getLayerRow(), ip, port, fms.getDeviceType());
                    logger.info("disk_sn:" + fms.getDeviceSn() + ",state:" + state);
                    _fmsService.update(new UpdateWrapper<DeviceMachineFms>().set("state", state)
                            .set("device_id", fms.getDeviceId()).eq("disk_sn", fms.getDeviceSn()));
                    if (state.equals("0")) {
                        logger.info("测试完毕,进入告警判断流程,fms-sn:" + fms.getDeviceSn());
                        DeviceMeasure measure = (DeviceMeasure) ConcurrentHashMapCacheUtils
                                .getCache(Constant.MSP2000MeasureNowMapPrefix + fms.getDeviceSn());
                        // 设备正处于告警判断状态，还无法启动测试
                        ConcurrentHashMapCacheUtils
                                .setCache(Constant.MSP2000FMSAlarmProcessPrefix + fms.getDeviceSn(), true, 300 * 1000);
                        ConcurrentHashMapCacheUtils
                                .deleteCache(Constant.MSP2000MeasureNowMapPrefix + fms.getDeviceSn());
                        // 需要下载sor
                        if (measure == null) {
                            logger.info("未找到对应的测试信息:" + fms.getDeviceSn());
                            return;
                        }
                        int sorType = 1;// 默认有限传输；
                        SorFileParser sor;
                        if (measure.getRouteId() != null && measure.getRouteId() > 0) {
                            DeviceRoute route = routeService.getById(measure.getRouteId());
                            if (route != null) {
                                sorType = route.getSorType();
                            }
                        }

                        if (sorType == 1) {
                            final byte[] bytes = fmsDeviceUtil.getFmsSor(fms.getLayerRow(), ip, port,
                                    fms.getDeviceType());
                            final String filePath = FTPUtils.saveStreamToDisk(bytes, "FMS-Disk.sor", fms.getDeviceSn());
                            measure.setSorPath(filePath);
                            sor = SORFileParserTool.parserSorFile(filePath);
                        } else {
                            // 新增无线传输，只获取事件
                            sor = fmsDeviceUtil.getFmsSorWireless(fms.getLayerRow(), ip, port, fms.getDeviceType());
                        }

                        // 循环监测需要设置当前设备测试时间
                        if (measure.getAction().equals(1)) {
                            if (ConcurrentHashMapCacheUtils
                                    .isExist(Constant.FmsDeviceAutoMeasureTime + fms.getDeviceSn())) {
                                ConcurrentHashMapCacheUtils.setCache(
                                        Constant.FmsDeviceAutoMeasureTime + fms.getDeviceSn(),
                                        DateUtils.getNowLocalDateTime());
                            }
                        }
                        measure.setMeasureStatus(3);
                        measure.setEndTime(LocalDateTime.now());

                        _snmpService.insertOrUpdateMeasureAndEvent(sor, measure, fms.getDeviceType());
                        // 异步判断告警
                        _msp2000AlarmProcess.parseFmsAlarm(measure, fms.getDeviceSn());
                    }
                    _fmsService.update(new UpdateWrapper<DeviceMachineFms>().set("state", state)
                            .set("device_id", fms.getDeviceId()).eq("disk_sn", fms.getDeviceSn()));
                } catch (Exception e) {
                    // 删除报警处理的key，以免影响自动测试
                    ConcurrentHashMapCacheUtils.deleteCache(Constant.MSP2000FMSAlarmProcessPrefix + fms.getDeviceSn());
                    logger.error(e.toString());
                }
            }
        }

    }

    /**
     * 离线路由中opm告警需要驱动otdr进行测试
     *
     */
    @Scheduled(fixedDelay = 1000 * 7)
    public void opmAlarmMeasureTask() throws InterruptedException {
        try {
            if (Msp2000DataCache.isEmptyOpmMeasureQueue())
                return;
            DeviceRouteConfig routeConfig = Msp2000DataCache.pollOpmMeasureQueue();
            if (routeConfig == null)
                return;
            DeviceRoute route = routeService.getById(routeConfig.getRouteId());
            // DeviceDevice fmsOrOswDevice = _devSvs.getDeviceBySn(route);
            DeviceDevice fms = _devSvs.getDeviceBySn(route.getFmsSn());
            DeviceDevice fmsParent = _devSvs.getById(fms.getParentId());
            DeviceDevice osw = _devSvs.getDeviceBySn(route.getOswSn());
            DeviceDevice oswParent = _devSvs.getById(osw.getParentId());
            String manualKey = Constant.MSP2000MeasureNowMapPrefix + fms.getDeviceSn();
            while (true) {
                boolean isExistMeasure = ConcurrentHashMapCacheUtils.isExist(manualKey);
                if (isExistMeasure) {
                    Thread.sleep(5000);
                } else {
                    break;
                }
            }
            String ip = fms.isOTDR() ? fms.getIpaddr() : fmsParent.getIpaddr();
            int port = fms.isOTDR() ? fms.getDevicePort() : fmsParent.getDevicePort();
            boolean setFmsResult = fmsDeviceUtil.setFmsConfig(fms.getLayerRow(), ip, port,
                    routeConfig.getEndPosition() + "", routeConfig.getPulseWidth() + "",
                    routeConfig.getResolution() + "",
                    fms.getDeviceType(), fms.getDeviceSn());
            if (setFmsResult) {
                // 设置光开关位置
                final boolean oswSetResult = oswDeviceUtil.setOswConfig(route.getOswSn(), routeConfig.getChannel() + "",
                        oswParent.getIpaddr(), oswParent.getDevicePort());
                startOTDR(routeConfig, fms, osw, manualKey, ip, port, oswSetResult, fmsDeviceUtil, 4);
            }
        } catch (Exception ex) {
            logger.error(ex.toString());
        }
    }

    /**
     * 启动FMS设备测试，并缓存测试，入库
     */
    private static void startOTDR(DeviceRouteConfig routeConfig, DeviceDevice fms, DeviceDevice osw, String manualKey,
            String ip, int port, boolean configResult, FmsDeviceUtil fmsDeviceUtil, int action) {
        if (configResult) {
            LocalDateTime now = LocalDateTime.now();
            boolean startResult = fmsDeviceUtil.startMeasure(fms.getLayerRow(), ip, port, fms.getDeviceType());
            if (startResult) {
                DeviceMeasure measure = new DeviceMeasure().setAverageNum(1).setDeviceId(osw.getDeviceId())
                        .setDeviceIp(osw.getIpaddr()).setDeptId(fms.getDeptId()).setAction(action)
                        .setDeviceSn(osw.getDeviceSn())
                        .setEndPosition(Double.valueOf(routeConfig.getEndPosition()).intValue())
                        .setPulseWidth(Double.valueOf(routeConfig.getPulseWidth()).intValue()).setMeasureStatus(2)
                        .setStartTime(now).setResolution(routeConfig.getResolution()).setCreateBy("system")
                        .setCreateTime(now).setChannel(routeConfig.getChannel())
                        .setRouteId(routeConfig.getRouteId());
                measure.setAutoTaskNum(CommonUtil.getOrderIdByUUId());
                measure.insert();
                ConcurrentHashMapCacheUtils.setCache(manualKey, measure);
            }
        }
    }

    /**
     * FSP路由告警驱动测试
     */
    @Scheduled(fixedDelay = 1000 * 5)
    public void fspRouteAlarmMeasureTask() throws InterruptedException {
        if (Msp2000DataCache.isEmptyFspMeasureQueue())
            return;
        DeviceFibreMatch deviceFibreMatch = Msp2000DataCache.pollFspMeasureQueue();
        if (deviceFibreMatch == null)
            return;
        // 判断绑定关系是属于哪种路由，轮询路由 需 先打光开关再测试
        final DeviceRoute deviceRoute = routeService.getById(deviceFibreMatch.getRouteId());
        if (deviceRoute == null) {
            logger.error("FSP驱动测试：route为空");
            return;
        }

        DeviceRouteConfig routeConfig = routeConfigService.selectByRouteIdAndChannel(deviceRoute.getRouteId(),
                deviceFibreMatch.getTargetDeviceChannel());
        if (routeConfig == null) {
            logger.error("FSP驱动测试：routeConfig为空");
            return;
        }
        RouteTypeEnum routeTypeEnum = RouteTypeEnum.valueOf(deviceRoute.getRouteType());
        DeviceDevice otdr;
        switch (routeTypeEnum) {
            case fspRoute:
                otdr = _devSvs.getDeviceBySn(deviceFibreMatch.getTargetDeviceSn());
                if (otdr == null) {
                    logger.error("FSP驱动测试：otdr为空");
                    return;
                }
                startNormalMeasure(otdr, routeConfig, otdr, 4);
                break;
            case pollingRoute:
                // 需要下发光开关设置
                logger.info("FSP驱动轮询路由测试：开始");
                DeviceDevice osw = _devSvs.getDeviceBySn(deviceRoute.getOswSn());
                if (osw == null) {
                    logger.info("FSP驱动轮询路由测试：未找到osw的设备");
                    return;
                }

                DeviceDevice oswParent = _devSvs.getById(osw.getParentId());
                final boolean oswSetResult = oswDeviceUtil.setOswConfig(deviceRoute.getOswSn(),
                        deviceFibreMatch.getTargetDeviceChannel() + "",
                        oswParent.getIpaddr(), oswParent.getDevicePort());
                if (!oswSetResult) {
                    logger.error("FSP驱动轮询路由测试：OSW参数设置不成功，请稍后再试");
                    return;
                }
                logger.info("FSP驱动轮询路由测试：OSW通道" + deviceFibreMatch.getTargetDeviceChannel() + "设置成功");
                otdr = _devSvs.getDeviceBySn(deviceRoute.getFmsSn());
                if (otdr == null) {
                    logger.info("FSP驱动轮询路由测试：otdr为空");
                    return;
                }
                // action= 4 ,FSP驱动轮询路由测试
                startNormalMeasure(otdr, routeConfig, osw, 4);
                break;
            case offlineRoute:
                break;
            case realTimeRoute:
                break;
            default:
                break;
        }
    }

    private void startNormalMeasure(DeviceDevice otdr, DeviceRouteConfig routeConfig, DeviceDevice osw, int action)
            throws InterruptedException {
        String manualKey = Constant.MSP2000MeasureNowMapPrefix + otdr.getDeviceSn();
        while (true) {
            boolean isExistMeasure = ConcurrentHashMapCacheUtils.isExist(manualKey);
            if (isExistMeasure) {
                Thread.sleep(2000);
            } else {
                break;
            }
        }
        String ip;
        int port;
        if (otdr.isFMS()) {
            DeviceDevice parent = _devSvs.getById(otdr.getParentId());
            ip = parent.getIpaddr();
            port = parent.getDevicePort();
        } else {
            ip = otdr.getIpaddr();
            port = otdr.getDevicePort();
        }
        boolean setFmsResult = fmsDeviceUtil.setFmsConfig(otdr.getLayerRow(), ip, port,
                routeConfig.getEndPosition() + "", routeConfig.getPulseWidth() + "", routeConfig.getResolution() + "",
                otdr.getDeviceType(), otdr.getDeviceSn());
        startOTDR(routeConfig, otdr, osw, manualKey, ip, port, setFmsResult, fmsDeviceUtil, action);
    }

    /**
     * 周期测试路由设备，默认每5s执行一次判断是否需要测试 1，读取osw绑定的光缆端口，2，读取配置参数,下发配置参数，3，设置光开关，4启动测试
     */
    @Scheduled(fixedDelay = 1000 * 5)
    public void autoMeasureTask() throws InterruptedException {
        List<DeviceRoute> routeList = routeService.list(new QueryWrapper<DeviceRoute>()
                .and(i -> i.eq("route_type", RouteTypeEnum.realTimeRoute.name()).or().eq("route_type",
                        RouteTypeEnum.pollingRoute.name()))
                .ge("auto_measure_interval", 0));
        for (DeviceRoute deviceRoute : routeList) {
            // 需要自动测试
            Object measureTime = ConcurrentHashMapCacheUtils
                    .getCache(Constant.AutoMeasureInterval + deviceRoute.getRouteId());
            // LocalDateTime now = LocalDateTime.now();
            int interval = deviceRoute.getAutoMeasureInterval();
            String measureDeviceSn = deviceRoute.getRouteType().equals(RouteTypeEnum.realTimeRoute.name())
                    ? deviceRoute.getFmsSn()
                    : deviceRoute.getOswSn();

            if (measureTime == null
                    || DateUtils.stringToLocalDateTime((String) measureTime).isBefore(LocalDateTime.now())) {
                final List<DeviceRouteConfig> configList = routeConfigService.selectByRouteId(deviceRoute.getRouteId());
                final List<DeviceFibreMatch> fibreMatches = matchService.selectByDeviceSn(measureDeviceSn);
                // 需要测试,对每个osw绑定对通道进行测试,osw信息用于新增测量任务的参数
                // 需要判断每个设备是否存在，不存在就继续循环
                DeviceDevice fms = _devSvs.getDeviceBySn(deviceRoute.getFmsSn());
                if (fms == null)
                    return;
                DeviceDevice parent = _devSvs.getById(fms.getParentId());
                if (parent == null)
                    return;
                DeviceDevice oswParent = null;
                if (deviceRoute.getRouteType().equals(RouteTypeEnum.pollingRoute.name())) {
                    // 设置光开关位置
                    DeviceDevice osw = _devSvs.getDeviceBySn(deviceRoute.getOswSn());
                    if (osw == null)
                        return;
                    oswParent = _devSvs.selectParentDeviceBySn(deviceRoute.getOswSn());
                    if (oswParent == null)
                        return;
                }

                String manualKey = Constant.MSP2000MeasureNowMapPrefix + fms.getDeviceSn();
                String alarmProcessKey = Constant.MSP2000FMSAlarmProcessPrefix + fms.getDeviceSn();

                DeviceDevice fmsOrOswDevice = _devSvs.getDeviceBySn(measureDeviceSn);
                for (DeviceFibreMatch fibreMatch : fibreMatches) {
                    // 先下发fms参数配置
                    while (true) {
                        boolean isExistMeasure = ConcurrentHashMapCacheUtils.isExist(manualKey);
                        if (isExistMeasure)
                            logger.info("设备正在测试:" + fms.getDeviceSn());
                        boolean isAlarmProcess = ConcurrentHashMapCacheUtils.isExist(alarmProcessKey);
                        if (isAlarmProcess)
                            logger.info("设备测完正在处理告警：" + fms.getDeviceSn());
                        if (isExistMeasure || isAlarmProcess) {
                            Thread.sleep(5000);
                        } else {
                            // 再次判断时间间隔是否超过指定间隔
                            measureTime = ConcurrentHashMapCacheUtils
                                    .getCache(Constant.FmsDeviceAutoMeasureTime + deviceRoute.getFmsSn());
                            if (measureTime == null || DateUtils.stringToLocalDateTime((String) measureTime)
                                    .isBefore(LocalDateTime.now().minusMinutes(interval))) {
                                break;
                            }
                        }
                    }
                    logger.info("设备测试完毕，准备测量下一通道,fms-sn：" + fms.getDeviceSn() + "路由id：" + deviceRoute.getRouteId()
                            + "，通道：" + fibreMatch.getChannel());
                    // 再次判断
                    boolean isExistMeasure = ConcurrentHashMapCacheUtils.isExist(manualKey);
                    if (isExistMeasure) {
                        logger.info("设备正在测试:" + fms.getDeviceSn());
                    }

                    boolean isAlarmProcess = ConcurrentHashMapCacheUtils.isExist(alarmProcessKey);
                    if (isAlarmProcess)
                        logger.info("设备测完正在处理告警：" + fms.getDeviceSn());
                    final Optional<DeviceRouteConfig> config = configList.stream()
                            .filter(r -> r.getChannel().equals(fibreMatch.getChannel())).findFirst();
                    if (config.isPresent()) {
                        String ip = fms.isOTDR() ? fms.getIpaddr() : parent.getIpaddr();
                        int port = fms.isOTDR() ? fms.getDevicePort() : parent.getDevicePort();
                        boolean setFmsResult = fmsDeviceUtil.setFmsConfig(fms.getLayerRow(), ip, port,
                                config.get().getEndPosition() + "", config.get().getPulseWidth() + "",
                                config.get().getResolution() + "", fms.getDeviceType(), fms.getDeviceSn());
                        if (setFmsResult) {
                            if (deviceRoute.getRouteType().equals("pollingRoute") && oswParent != null) {
                                // 设置光开关位置
                                final boolean oswSetResult = oswDeviceUtil.setOswConfig(deviceRoute.getOswSn(),
                                        fibreMatch.getChannel() + "", oswParent.getIpaddr(), oswParent.getDevicePort());
                                if (!oswSetResult) {
                                    // 设置错误，等待下次再尝试
                                    continue;
                                }
                            }
                            // 启动FMS设备测试
                            LocalDateTime now = LocalDateTime.now();
                            boolean startResult = fmsDeviceUtil.startMeasure(fms.getLayerRow(), ip, port,
                                    fms.getDeviceType());
                            if (startResult) {
                                DeviceMeasure measure = new DeviceMeasure().setAverageNum(1)
                                        .setDeviceId(fmsOrOswDevice.getDeviceId()).setDeviceIp(parent.getIpaddr())
                                        .setDeptId(fmsOrOswDevice.getDeptId()).setAction(1)
                                        .setDeviceSn(fmsOrOswDevice.getDeviceSn())
                                        .setEndPosition(Double.valueOf(config.get().getEndPosition()).intValue())
                                        .setPulseWidth(Double.valueOf(config.get().getPulseWidth()).intValue())
                                        .setMeasureStatus(2).setStartTime(now)
                                        .setResolution(config.get().getResolution()).setCreateBy("system")
                                        .setCreateTime(now).setChannel(fibreMatch.getChannel())
                                        .setRouteId(deviceRoute.getRouteId());
                                measure.setAutoTaskNum(CommonUtil.getOrderIdByUUId());
                                measure.insert();
                                ConcurrentHashMapCacheUtils.setCache(manualKey, measure);
                                logger.info("自动测试启动成功：" + "fms-sn：" + fms.getDeviceSn() + "路由id："
                                        + deviceRoute.getRouteId() + "，通道：" + fibreMatch.getChannel());
                            }
                        }
                    }

                }

                final DeviceMachineFms deviceMachineFms = _fmsService.selectLastFmsData(fms.getDeviceSn());
                int measureInterval;// 秒
                if (deviceMachineFms == null || deviceMachineFms.getMeasureTime() == null
                        || deviceMachineFms.getMeasureTime() <= 0) {
                    measureInterval = interval * 60 + 50;
                } else {
                    measureInterval = interval * 60 + deviceMachineFms.getMeasureTime() + 20;// 测量时间加20
                }
                ConcurrentHashMapCacheUtils.setCache(Constant.AutoMeasureInterval + deviceRoute.getRouteId(),
                        DateUtils.formatLocalDateTimeDefault(LocalDateTime.now().plusSeconds(measureInterval)));
                // deviceRoute.getAutoMeasureInterval()
            }
        }
    }

    /**
     * 启动OTDR等设备 数据拉取定时任务,fms-m(otdr)、fms-a均为ip直连，fms为主控控制
     */
    @Scheduled(fixedDelay = 1000 * 5)
    public void sendPollCommandManual() {
        final List<DeviceDevice> otdrList = _devSvs.getOtdrDevice();
        for (DeviceDevice otdr : otdrList) {
            DeviceDevice parent = _devSvs.getById(otdr.getParentId());
            String ip = otdr.isOTDR() ? otdr.getIpaddr() : parent.getIpaddr();
            int port = otdr.isOTDR() ? otdr.getDevicePort() : parent.getDevicePort();
            DeviceMachineFms fmsData = fmsDeviceUtil.getFmsData(otdr.getLayerRow(), ip, port, Constant.FMSM);
            if (fmsData == null) {
                continue;
            }
            fmsData.setDeviceId(otdr.getDeviceId());
            fmsData.setDiskSn(otdr.getDeviceSn());
            String state = fmsDeviceUtil.getFmsStatus(otdr.getLayerRow(), ip, port, otdr.getDeviceType());
            fmsData.setState(state);
            final DeviceMachineFms machineFms = _fmsService.selectLastFmsData(fmsData.getDiskSn());
            if (machineFms != null) {
                _fmsService.update(fmsData,
                        new LambdaQueryWrapper<DeviceMachineFms>().eq(DeviceMachineFms::getMachineFmsId,
                                machineFms.getMachineFmsId()));
            } else {
                fmsData.insert();
            }
        }
    }

    /**
     * 启动MSP2000设备 数据拉取定时任务
     */
    @Scheduled(fixedDelay = 1000 * 10)
    public void sendPollCommandMSP2000() {
        final List<DeviceDevice> dbDeviceList = _devSvs.listByType(Constant.MSP2000);
        List<String> deviceSnList = new ArrayList<>();
        for (final DeviceDevice device : dbDeviceList) {
            if (StringUtils.isEmpty(device.getDeviceSn())) {
                continue;
            }
            String body = _udpClient.getBodyBySendUdp(device.getIpaddr(), device.getDevicePort());
            if (StringUtils.isEmpty(body)) {
                int errorTimes = 0;
                Object cacheTime = ConcurrentHashMapCacheUtils.getCache(device.getDeviceSn() + ":error");
                if (cacheTime != null) {
                    errorTimes = (int) cacheTime;
                }
                errorTimes++;
                ConcurrentHashMapCacheUtils.setCache(device.getDeviceSn() + ":error", errorTimes);
                if (errorTimes >= 3) {// 超过3次就插入一条报警数据，后面则更新该告警
                    DeviceAlarmRealtime dbAlarm = _alarmRealtimeService.getLastOneExistAlarm(device.getDeviceSn(),
                            "DEVICE_CONNECT_ERROR", -1);
                    if (dbAlarm != null) {
                        dbAlarm.setLastTime(LocalDateTime.now());
                        dbAlarm.updateById();
                    } else {
                        DeviceAlarmRealtime alarm = new DeviceAlarmRealtime();
                        alarm.setAlarmMsg(device.getDeviceName() + ":设备不在位");
                        alarm.setDeptId(device.getDeptId());
                        alarm.setDeviceId(device.getDeviceId());
                        alarm.setDeviceSn(device.getDeviceSn());
                        alarm.setDataType("MSP2000");
                        DeviceAlarmType alarmType = SnmpDataCache.getAlarmTypeListByCode("DEVICE_CONNECT_ERROR", "");
                        alarm.setAlarmTypeId(alarmType.getAlarmTypeId());
                        alarm.setAlarmLevel(alarmType.getAlarmLevelCode());
                        alarm.setAlarmTypeName(alarmType.getAlarmTypeName());
                        alarm.setAlarmTypeCode(alarmType.getAlarmTypeCode());
                        alarm.setStartTime(LocalDateTime.now());
                        alarm.setProcessed(false);
                        alarm.setLastTime(LocalDateTime.now());
                        alarm.setCreateTime(LocalDateTime.now());
                        alarm.insert();
                    }
                }
                continue;
            }
            DeviceAlarmRealtime dbAlarm = _alarmRealtimeService.getLastOneExistAlarm(device.getDeviceSn(),
                    "DEVICE_CONNECT_ERROR", -1);
            LocalDateTime now = LocalDateTime.now();
            if (dbAlarm != null) {
                _alarmHistoryService.saveByRealtimeAlarm(dbAlarm);
                dbAlarm.deleteById();
                ConcurrentHashMapCacheUtils.deleteCache(device.getDeviceSn() + ":error");
            }
            DeviceMachineFrame mFrame = DataParse.parseDeviceMachineFrame(body.substring(0, 88));
            if (device.getDeviceSn() == null || !device.getDeviceSn().equals(mFrame.getFrameSn())) {
                device.setDeviceSn(mFrame.getFrameSn());
                device.updateById();
            }
            mFrame.setDeviceId(device.getDeviceId());
            _frameService.saveOrUpdate(mFrame,
                    new UpdateWrapper<DeviceMachineFrame>().eq("frame_sn", mFrame.getFrameSn()));
            // 更新或插入机架信息
            DeviceMachineRack rack = DataParse.parseDeviceMachineRack(body.substring(88, 88 + 24 * 2));
            rack.setFrameSn(mFrame.getFrameSn());
            _rackService.saveOrUpdate(rack, new UpdateWrapper<DeviceMachineRack>().eq("rack_sn", rack.getRackSn()));
            // List<Integer> diskStrList = new ArrayList<>();// 所有disk
            body = body.substring(136);
            boolean hasUnknowDevice = false;// 是否有未知设备
            for (int j = 0; j < rack.getSlotNumber(); j++) {
                SlotData s = DataParse.parseSlotData(body);
                DeviceMachineDisk disk = DataParse.parseDeviceMachineDisk(s);
                disk.setRackSn(rack.getRackSn());
                _diskService.saveOrUpdate(disk, new UpdateWrapper<DeviceMachineDisk>().eq("disk_sn", disk.getDiskSn()));
                // 添加设备sn到当前设备sn列表，然后删除数据库不存在的设备
                deviceSnList.add(s.getSn());
                String subSn = s.getSn().substring(s.getSn().length() - 6);
                // 根据sn查询单盘 并更新单盘位置
                DeviceDevice dbDevice = _devSvs.getDeviceDiskBySn(s.getSn());
                if (dbDevice != null) {
                    dbDevice.setLayerRow(s.getSlotPort());
                    dbDevice.setParentId(device.getDeviceId());
                    dbDevice.updateById();
                }
                switch (s.getType()) {
                    case "30A":
                        FanPlate fan = DataParse.parseFanPlate(s.getBody());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("FAN@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.FAN.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            // dbDevice.insert();
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);

                        }
                        DeviceDevice finalDbDevice = dbDevice;
                        fan.getFans().forEach(
                                item -> item.setDeviceId(finalDbDevice.getDeviceId()).setDiskSn(disk.getDiskSn()));
                        fan.getPowers().forEach(item -> item.setDiskSn(disk.getDiskSn()));
                        finalDbDevice.setParentId(device.getDeviceId());
                        finalDbDevice.updateById();
                        _msp2000AlarmProcess.fanAlarm(fan, finalDbDevice);

                        _powerService.saveBatch(fan.getPowers());
                        _fanService.saveBatch(fan.getFans());
                        _msp2000AlarmProcess.parsePowerAlarm(fan.getPowers());
                        break;
                    case "330":
                        DeviceMachineFsp fsp = DataParse.parseDeviceMachineFsp(s.getBody());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("FSP6@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.FSP6.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        fsp.setDiskSn(disk.getDiskSn());
                        fsp.setDeviceId(dbDevice.getDeviceId());
                        _fspService.save(fsp);
                        _msp2000AlarmProcess.fspAlarm(fsp, dbDevice);
                        break;
                    case "320":
                        DeviceMachineEdfa edfa = DataParse.parseDeviceMachineEdfa(s.getBody());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("EDFA@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.EDFA.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        edfa.setDeviceId(dbDevice.getDeviceId());
                        edfa.setDiskSn(disk.getDiskSn());
                        _edfaService.save(edfa);
                        _msp2000AlarmProcess.edfaAlarm(edfa, dbDevice);
                        break;
                    case "321":
                        DeviceMachineRfa rfa = DataParse.parseDeviceMachineRfa(s.getBody());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("RFA@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.RFA.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        rfa.setDeviceId(dbDevice.getDeviceId());
                        rfa.setDiskSn(disk.getDiskSn());
                        rfa.insert();
                        _msp2000AlarmProcess.rfaAlarm(rfa, dbDevice);
                        break;
                    case "323":
                        DeviceMachineRt rt = DataParse.parseDeviceMachineRt(s.getBody());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("RT@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.RT.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        rt.setDeviceId(dbDevice.getDeviceId());
                        rt.setDiskSn(disk.getDiskSn());
                        _rtService.save(rt);
                        _msp2000AlarmProcess.rtAlarm(rt, dbDevice);
                        break;
                    case "371":
                        DeviceMachineFec fec = DataParse.parseDeviceMachineFec(s.getBody(), "2.5");
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("FEC2.5G@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.FEC16.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        fec.setDeviceId(dbDevice.getDeviceId());
                        fec.setDiskSn(disk.getDiskSn());
                        _fecService.save(fec);
                        fec.getFecModuleList().forEach(item -> item.setMachineFecId(fec.getMachineFecId()));
                        _fecModuleService.saveBatch(fec.getFecModuleList());
                        _msp2000AlarmProcess.fecAlarm(fec, dbDevice);
                        break;
                    case "370":
                        DeviceMachineFec fec1 = DataParse.parseDeviceMachineFec(s.getBody(), "10");
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("FEC10G@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.FEC64.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        fec1.setDeviceId(dbDevice.getDeviceId());
                        fec1.setDiskSn(disk.getDiskSn());
                        _fecService.save(fec1);
                        fec1.getFecModuleList().forEach(item -> item.setMachineFecId(fec1.getMachineFecId()));
                        _fecModuleService.saveBatch(fec1.getFecModuleList());
                        _msp2000AlarmProcess.fecAlarm(fec1, dbDevice);
                        break;
                    case "3B0":
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("HUB@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.HUB.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        break;
                    case "3B6":
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("E1@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.E1.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        break;

                    case "3D2":
                        DeviceMachineOpm opm = DataParse.paserOpm(s.getBody(), s.getSn());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("OPM@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.OPM.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        opm.setDeviceId(dbDevice.getDeviceId());
                        opm.setDiskSn(disk.getDiskSn());
                        opm.insert();
                        opm.getOpmModuleList().forEach(item -> item.setMachineOpmId(opm.getMachineOpmId()));
                        _opmModuleService.saveBatch(opm.getOpmModuleList());
                        _msp2000AlarmProcess.parseOpmData(opm);
                        break;
                    case "3D0":
                        if (StringUtils.isEmpty(s.getBody())) {
                            break;
                        }
                        DeviceMachineOsw osw = DataParse.paserOsw(s.getBody(), s.getSn());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("OSW@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.OSW.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        osw.setDeviceId(dbDevice.getDeviceId());
                        osw.setDiskSn(disk.getDiskSn());
                        _oswService.save(osw);
                        break;
                    case "3D1":
                        DeviceMachineOs os = DataParse.paserOs(s.getBody(), s.getSn());
                        if (dbDevice == null) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(s.getSn())
                                    .setDeviceName("OS@" + subSn).setDeviceModel(s.getType())
                                    .setDeviceType(DiskTypeEnum.OS.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(s.getSlotPort()).setCreateTime(now).setDeviceDigest(Constant.MSP2000);
                            _devSvs.deleteBySlopAndInsertNew(s.getSlotPort(), device.getDeviceId(), dbDevice);
                        }
                        os.setDeviceId(dbDevice.getDeviceId());
                        os.setDiskSn(disk.getDiskSn());
                        os.insert();
                        os.getOsModuleList().forEach(item -> item.setMachineOsId(os.getMachineOsId()));
                        _osModuleService.saveBatch(os.getOsModuleList());
                        break;
                    default:
                        hasUnknowDevice = true;

                        System.out.println("未识别类型：" + s.getType());
                }
                body = body.substring(s.getAllLen());

            }

            if (hasUnknowDevice) {
                System.out.println("需要读取电子标签");
                String pollCmd = DataBuild.buildFF01Msg();
                String parseData = _udpClient.sendPollCommand(device.getIpaddr(), device.getDevicePort(), pollCmd);
                Msp2000Ter2Platform msg = DataParse.parseAllMsg(ByteUtil.hexToBytes(parseData));

                if (msg.getData().startsWith("6E9E")) {
                    ElectronicTags e = DataParse.parseElectronicTags(msg.getData());
                    for (DeviceMachineDisk disk : e.edata.eTSlotDatas) {
                        // 单盘标签
                        Optional<String> first = deviceSnList.stream().filter(r -> r.equals(disk.getDiskSn()))
                                .findFirst();
                        if (first.isPresent()) {
                            continue;
                        }
                        if (_devSvs.getDeviceBySn(disk.getDiskSn()) != null) {
                            deviceSnList.add(disk.getDiskSn());
                            continue;
                        }

                        String diskType = disk.getDiskSn().substring(3, 6);
                        DeviceDevice dbDevice;
                        String subSn = disk.getDiskSn().substring(disk.getDiskSn().length() - 6);
                        if (diskType.equals("3D3")) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(disk.getDiskSn())
                                    .setDeviceName("FMS@" + subSn).setDeviceModel(diskType)
                                    .setDeviceType(DiskTypeEnum.FMS.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(disk.getSlotPort()).setCreateTime(LocalDateTime.now())
                                    .setDeviceDigest(Constant.MSP2000);

                        } else if (diskType.equals("30A")) {
                            dbDevice = new DeviceDevice().setDeptId(device.getDeptId()).setDeviceSn(disk.getDiskSn())
                                    .setDeviceName("FAN@" + subSn).setDeviceModel(diskType)
                                    .setDeviceType(DiskTypeEnum.FAN.name()).setParentId(device.getDeviceId())
                                    .setLayerRow(disk.getSlotPort()).setCreateTime(LocalDateTime.now())
                                    .setDeviceDigest(Constant.MSP2000);
                        } else {
                            continue;
                        }
                        if (dbDevice != null) {
                            _devSvs.deleteBySlopAndInsertNew(disk.getSlotPort(), device.getDeviceId(), dbDevice);
                            deviceSnList.add(dbDevice.getDeviceSn());
                        }

                    }

                }
            }
        }
        sendRefreshToWebsocketClient();
    }

    /**
     * 推送消息到web客户端,只刷新下面的报警内容
     */
    void sendRefreshToWebsocketClient() {
        JSONObject json = new JSONObject();
        json.put("msgType", 0);// 0=refresh data
        try {
            MyWebSocket.sendToAllClient(json.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 自动删除多余数据服务
     */
    @Scheduled(cron = "0 0/1 * * * ? ")
    public void autoDeleteNoUsedDataScheduled() {
        aboutService.deleteNoUsedData();
    }
}
